home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / libtiff / tools / tiffcmp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  13.6 KB  |  484 lines

  1. /* $Header: /usr/people/sam/tiff/tools/RCS/tiffcmp.c,v 1.29 1996/01/10 19:35:36 sam Rel $ */
  2.  
  3. /*
  4.  * Copyright (c) 1988-1996 Sam Leffler
  5.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "tiffio.h"
  32.  
  33. static    int stopondiff = 1;
  34. static    int stoponfirsttag = 1;
  35. static    uint16 bitspersample = 1;
  36. static    uint16 samplesperpixel = 1;
  37. static    uint32 imagewidth;
  38. static    uint32 imagelength;
  39.  
  40. static    int tiffcmp(TIFF*, TIFF*);
  41. static    int cmptags(TIFF*, TIFF*);
  42. static    void ContigCompare(int, uint32, unsigned char*, unsigned char*, int);
  43. static    void PrintDiff(uint32, int, uint32, int, int);
  44. static    void SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
  45. static    void eof(const char*, uint32, int);
  46.  
  47. static void
  48. usage(void)
  49. {
  50.     fprintf(stderr, "Usage: tiffcmp [-l] [-t] [-z] file1 file2\n");
  51.     exit(-3);
  52. }
  53.  
  54. int
  55. main(int argc, char* argv[])
  56. {
  57.     TIFF *tif1, *tif2;
  58.     int c, dirnum;
  59.     extern int optind;
  60.  
  61.     while ((c = getopt(argc, argv, "ltz")) != -1)
  62.         switch (c) {
  63.         case 'l':
  64.             stopondiff = 0;
  65.             break;
  66.         case 'z':
  67.             stopondiff += 100;
  68.             break;
  69.         case 't':
  70.             stoponfirsttag = 0;
  71.             break;
  72.         case '?':
  73.             usage();
  74.             /*NOTREACHED*/
  75.         }
  76.     if (argc - optind < 2)
  77.         usage();
  78.     tif1 = TIFFOpen(argv[optind], "r");
  79.     if (tif1 == NULL)
  80.         return (-1);
  81.     tif2 = TIFFOpen(argv[optind+1], "r");
  82.     if (tif2 == NULL)
  83.         return (-2);
  84.     dirnum = 0;
  85.     while (tiffcmp(tif1, tif2)) {
  86.         if (!TIFFReadDirectory(tif1)) {
  87.             if (!TIFFReadDirectory(tif2))
  88.                 break;
  89.             printf("No more directories for %s\n",
  90.                 TIFFFileName(tif1));
  91.             return (1);
  92.         } else if (!TIFFReadDirectory(tif2)) {
  93.             printf("No more directories for %s\n",
  94.                 TIFFFileName(tif2));
  95.             return (1);
  96.         }
  97.         printf("Directory %d:\n", ++dirnum);
  98.     }
  99.     return (0);
  100. }
  101.  
  102. #define    checkEOF(tif, row, sample) { \
  103.     eof(TIFFFileName(tif), row, sample); \
  104.     goto bad; \
  105. }
  106.  
  107. static    int CheckShortTag(TIFF*, TIFF*, int, char*);
  108. static    int CheckShort2Tag(TIFF*, TIFF*, int, char*);
  109. static    int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
  110. static    int CheckLongTag(TIFF*, TIFF*, int, char*);
  111. static    int CheckFloatTag(TIFF*, TIFF*, int, char*);
  112. static    int CheckStringTag(TIFF*, TIFF*, int, char*);
  113.  
  114. static int
  115. tiffcmp(TIFF* tif1, TIFF* tif2)
  116. {
  117.     uint16 config1, config2;
  118.     tsize_t size1;
  119.     uint32 s, row;
  120.     unsigned char *buf1, *buf2;
  121.  
  122.     if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
  123.         return (0);
  124.     if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
  125.         return (0);
  126.     if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
  127.         return (0);
  128.     if (!cmptags(tif1, tif2))
  129.         return (1);
  130.     (void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  131.     (void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  132.     (void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
  133.     (void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
  134.     (void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
  135.     (void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
  136.     buf1 = (unsigned char *)_TIFFmalloc(size1 = TIFFScanlineSize(tif1));
  137.     buf2 = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2));
  138.     if (buf1 == NULL || buf2 == NULL) {
  139.         fprintf(stderr, "No space for scanline buffers\n");
  140.         exit(-1);
  141.     }
  142.     if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
  143.         fprintf(stderr,
  144. "Can't handle different planar configuration w/ different bits/sample\n");
  145.         goto bad;
  146.     }
  147. #define    pack(a,b)    ((a)<<8)|(b)
  148.     switch (pack(config1, config2)) {
  149.     case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
  150.         for (row = 0; row < imagelength; row++) {
  151.             if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
  152.                 checkEOF(tif2, row, -1)
  153.             for (s = 0; s < samplesperpixel; s++) {
  154.                 if (TIFFReadScanline(tif1, buf1, row, s) < 0)
  155.                     checkEOF(tif1, row, s)
  156.                 SeparateCompare(1, s, row, buf2, buf1);
  157.             }
  158.         }
  159.         break;
  160.     case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
  161.         for (row = 0; row < imagelength; row++) {
  162.             if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
  163.                 checkEOF(tif1, row, -1)
  164.             for (s = 0; s < samplesperpixel; s++) {
  165.                 if (TIFFReadScanline(tif2, buf2, row, s) < 0)
  166.                     checkEOF(tif2, row, s)
  167.                 SeparateCompare(0, s, row, buf1, buf2);
  168.             }
  169.         }
  170.         break;
  171.     case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
  172.         for (s = 0; s < samplesperpixel; s++)
  173.             for (row = 0; row < imagelength; row++) {
  174.                 if (TIFFReadScanline(tif1, buf1, row, s) < 0)
  175.                     checkEOF(tif1, row, s)
  176.                 if (TIFFReadScanline(tif2, buf2, row, s) < 0)
  177.                     checkEOF(tif2, row, s)
  178.                 ContigCompare(s, row, buf1, buf2, size1);
  179.             }
  180.         break;
  181.     case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
  182.         for (row = 0; row < imagelength; row++) {
  183.             if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
  184.                 checkEOF(tif1, row, -1)
  185.             if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
  186.                 checkEOF(tif2, row, -1)
  187.             ContigCompare(-1, row, buf1, buf2, size1);
  188.         }
  189.         break;
  190.     }
  191.     if (buf1) _TIFFfree(buf1);
  192.     if (buf2) _TIFFfree(buf2);
  193.     return (1);
  194. bad:
  195.     if (stopondiff)
  196.         exit(1);
  197.     if (buf1) _TIFFfree(buf1);
  198.     if (buf2) _TIFFfree(buf2);
  199.     return (0);
  200. }
  201.  
  202. #define    CmpShortField(tag, name) \
  203.     if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  204. #define    CmpShortField2(tag, name) \
  205.     if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  206. #define    CmpLongField(tag, name) \
  207.     if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  208. #define    CmpFloatField(tag, name) \
  209.     if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  210. #define    CmpStringField(tag, name) \
  211.     if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  212. #define    CmpShortArrayField(tag, name) \
  213.     if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
  214.  
  215. static int
  216. cmptags(TIFF* tif1, TIFF* tif2)
  217. {
  218.     CmpLongField(TIFFTAG_SUBFILETYPE,    "SubFileType");
  219.     CmpLongField(TIFFTAG_IMAGEWIDTH,    "ImageWidth");
  220.     CmpLongField(TIFFTAG_IMAGELENGTH,    "ImageLength");
  221.     CmpShortField(TIFFTAG_BITSPERSAMPLE,    "BitsPerSample");
  222.     CmpShortField(TIFFTAG_COMPRESSION,    "Compression");
  223.     CmpShortField(TIFFTAG_PREDICTOR,    "Predictor");
  224.     CmpShortField(TIFFTAG_PHOTOMETRIC,    "PhotometricInterpretation");
  225.     CmpShortField(TIFFTAG_THRESHHOLDING,    "Thresholding");
  226.     CmpShortField(TIFFTAG_FILLORDER,    "FillOrder");
  227.     CmpShortField(TIFFTAG_ORIENTATION,    "Orientation");
  228.     CmpShortField(TIFFTAG_SAMPLESPERPIXEL,    "SamplesPerPixel");
  229.     CmpShortField(TIFFTAG_MINSAMPLEVALUE,    "MinSampleValue");
  230.     CmpShortField(TIFFTAG_MAXSAMPLEVALUE,    "MaxSampleValue");
  231.     CmpFloatField(TIFFTAG_XRESOLUTION,    "XResolution");
  232.     CmpFloatField(TIFFTAG_YRESOLUTION,    "YResolution");
  233.     CmpLongField(TIFFTAG_GROUP3OPTIONS,    "Group3Options");
  234.     CmpLongField(TIFFTAG_GROUP4OPTIONS,    "Group4Options");
  235.     CmpShortField(TIFFTAG_RESOLUTIONUNIT,    "ResolutionUnit");
  236.     CmpShortField(TIFFTAG_PLANARCONFIG,    "PlanarConfiguration");
  237.     CmpLongField(TIFFTAG_ROWSPERSTRIP,    "RowsPerStrip");
  238.     CmpFloatField(TIFFTAG_XPOSITION,    "XPosition");
  239.     CmpFloatField(TIFFTAG_YPOSITION,    "YPosition");
  240.     CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
  241.     CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
  242. #ifdef notdef
  243.     { uint16 *graycurve;
  244.       CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
  245.     }
  246.     { uint16 *red, *green, *blue;
  247.       CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
  248.     }
  249.     { uint16 *red, *green, *blue;
  250.       CmpField3(TIFFTAG_COLORMAP, red, green, blue);
  251.     }
  252. #endif
  253.     CmpShortField2(TIFFTAG_PAGENUMBER,    "PageNumber");
  254.     CmpStringField(TIFFTAG_ARTIST,        "Artist");
  255.     CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
  256.     CmpStringField(TIFFTAG_MAKE,        "Make");
  257.     CmpStringField(TIFFTAG_MODEL,        "Model");
  258.     CmpStringField(TIFFTAG_SOFTWARE,    "Software");
  259.     CmpStringField(TIFFTAG_DATETIME,    "DateTime");
  260.     CmpStringField(TIFFTAG_HOSTCOMPUTER,    "HostComputer");
  261.     CmpStringField(TIFFTAG_PAGENAME,    "PageName");
  262.     CmpStringField(TIFFTAG_DOCUMENTNAME,    "DocumentName");
  263.     CmpShortField(TIFFTAG_MATTEING,        "Matteing");
  264.     CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
  265.     return (1);
  266. }
  267.  
  268. static void
  269. ContigCompare(int sample, uint32 row, unsigned char* p1, unsigned char* p2, int size)
  270. {
  271.     register uint32 pix;
  272.     register int ppb = 8/bitspersample;
  273.  
  274.     if (memcmp(p1, p2, size) == 0)
  275.         return;
  276.     switch (bitspersample) {
  277.     case 1: case 2: case 4: case 8: {
  278.         register unsigned char *pix1 = p1, *pix2 = p2;
  279.  
  280.         for (pix = 0; pix < imagewidth; pix1++, pix2++, pix += ppb)
  281.             if (*pix1 != *pix2)
  282.                 PrintDiff(row, sample, pix,
  283.                     *pix1, *pix2);
  284.         break;
  285.     }
  286.     case 16: {
  287.         register uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
  288.  
  289.         for (pix = 0; pix < imagewidth; pix1++, pix2++, pix++)
  290.             if (*pix1 != *pix2)
  291.                 PrintDiff(row, sample, pix,
  292.                     *pix1, *pix2);
  293.         break;
  294.     }
  295.     }
  296. }
  297.  
  298. static void
  299. PrintDiff(uint32 row, int sample, uint32 pix, int w1, int w2)
  300. {
  301.     register int mask1, mask2, s, bps;
  302.  
  303.     if (sample < 0)
  304.         sample = 0;
  305.     bps = bitspersample;
  306.     switch (bps) {
  307.     case 1:
  308.     case 2:
  309.     case 4:
  310.         mask1 =  ~((-1)<<bps);
  311.         s = (8-bps);
  312.         mask2 = mask1<<s;
  313.         for (; mask2; mask2 >>= bps, s -= bps, pix++) {
  314.             if ((w1 & mask2) ^ (w2 & mask2)) {
  315.                 printf(
  316.             "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
  317.                         (long) row, (long) pix,
  318.                     sample, (w1 >> s) & mask1,
  319.                     (w2 >> s) & mask1 );
  320.                 if (--stopondiff == 0)
  321.                     exit(1);
  322.             }
  323.         }
  324.         break;
  325.     case 8: 
  326.         printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
  327.             (long) row, (long) pix, sample, w1, w2);
  328.         if (--stopondiff)
  329.             exit(1);
  330.         break;
  331.     case 16:
  332.         printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
  333.             (long) row, (long) pix, sample, w1, w2);
  334.         if (--stopondiff)
  335.             exit(1);
  336.         break;
  337.     }
  338. }
  339.  
  340. static void
  341. SeparateCompare(int reversed, int sample, uint32 row, unsigned char* cp1, unsigned char* p2)
  342. {
  343.     uint32 npixels = imagewidth;
  344.     register int pixel;
  345.  
  346.     cp1 += sample;
  347.     for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++)
  348.         if (*cp1 != *p2) {
  349.             printf("Scanline %lu, pixel %lu, sample %ld: ",
  350.                 (long) row, (long) pixel, (long) sample);
  351.             if (reversed)
  352.                 printf("%02x %02x\n", *p2, *cp1);
  353.             else
  354.                 printf("%02x %02x\n", *cp1, *p2);
  355.             if (--stopondiff)
  356.                 exit(1);
  357.         }
  358. }
  359.  
  360. static int
  361. checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
  362. {
  363.  
  364.     if (TIFFGetField(tif1, tag, p1)) {
  365.         if (!TIFFGetField(tif2, tag, p2)) {
  366.             printf("%s tag appears only in %s\n",
  367.                 name, TIFFFileName(tif1));
  368.             return (0);
  369.         }
  370.         return (1);
  371.     } else if (TIFFGetField(tif2, tag, p2)) {
  372.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  373.         return (0);
  374.     }
  375.     return (-1);
  376. }
  377.  
  378. #define    CHECK(cmp, fmt) {                \
  379.     switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) {    \
  380.     case 1:    if (cmp)                \
  381.     case -1:    return (1);            \
  382.         printf(fmt, name, v1, v2);        \
  383.     }                        \
  384.     return (0);                    \
  385. }
  386.  
  387. static int
  388. CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  389. {
  390.     uint16 v1, v2;
  391.     CHECK(v1 == v2, "%s: %u %u\n");
  392. }
  393.  
  394. static int
  395. CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  396. {
  397.     uint16 v11, v12, v21, v22;
  398.  
  399.     if (TIFFGetField(tif1, tag, &v11, &v12)) {
  400.         if (!TIFFGetField(tif2, tag, &v21, &v22)) {
  401.             printf("%s tag appears only in %s\n",
  402.                 name, TIFFFileName(tif1));
  403.             return (0);
  404.         }
  405.         if (v11 == v21 && v12 == v22)
  406.             return (1);
  407.         printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
  408.     } else if (TIFFGetField(tif2, tag, &v21, &v22))
  409.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  410.     else
  411.         return (1);
  412.     return (0);
  413. }
  414.  
  415. static int
  416. CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  417. {
  418.     uint16 n1, *a1;
  419.     uint16 n2, *a2;
  420.  
  421.     if (TIFFGetField(tif1, tag, &n1, &a1)) {
  422.         if (!TIFFGetField(tif2, tag, &n2, &a2)) {
  423.             printf("%s tag appears only in %s\n",
  424.                 name, TIFFFileName(tif1));
  425.             return (0);
  426.         }
  427.         if (n1 == n2) {
  428.             char* sep;
  429.             uint16 i;
  430.  
  431.             if (memcmp(a1, a2, n1) == 0)
  432.                 return (1);
  433.             printf("%s: value mismatch, <%u:", name, n1);
  434.             sep = "";
  435.             for (i = 0; i < n1; i++)
  436.                 printf("%s%u", sep, a1[i]), sep = ",";
  437.             printf("> and <%u: ", n2);
  438.             sep = "";
  439.             for (i = 0; i < n2; i++)
  440.                 printf("%s%u", sep, a2[i]), sep = ",";
  441.             printf(">\n");
  442.         } else
  443.             printf("%s: %u items in %s, %u items in %s", name,
  444.                 n1, TIFFFileName(tif1),
  445.                 n2, TIFFFileName(tif2)
  446.             );
  447.     } else if (TIFFGetField(tif2, tag, &n2, &a2))
  448.         printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
  449.     else
  450.         return (1);
  451.     return (0);
  452. }
  453.  
  454. static int
  455. CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  456. {
  457.     uint32 v1, v2;
  458.     CHECK(v1 == v2, "%s: %lu %lu\n");
  459. }
  460.  
  461. static int
  462. CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  463. {
  464.     float v1, v2;
  465.     CHECK(v1 == v2, "%s: %g %g\n");
  466. }
  467.  
  468. static int
  469. CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
  470. {
  471.     char *v1, *v2;
  472.     CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
  473. }
  474.  
  475. static void
  476. eof(const char* name, uint32 row, int s)
  477. {
  478.  
  479.     printf("%s: EOF at scanline %lu", name, row);
  480.     if (s >= 0)
  481.         printf(", sample %d", s);
  482.     printf("\n");
  483. }
  484.